/**
 * 版权所有 2009-2012山东新北洋信息技术股份有限公司
 * 保留所有权利。
 */
package com.linyaonan.leetcode.medium._289;

import javax.swing.*;
import java.util.Arrays;

/**
 * 根据 百度百科 ，生命游戏，简称为生命，是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
 * <p>
 * 给定一个包含 m × n 个格子的面板，每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态：1 即为活细胞（live），或 0 即为死细胞（dead）。每个细胞与其八个相邻位置（水平，垂直，对角线）的细胞都遵循以下四条生存定律：
 * <p>
 * 如果活细胞周围八个位置的活细胞数少于两个，则该位置活细胞死亡；
 * 如果活细胞周围八个位置有两个或三个活细胞，则该位置活细胞仍然存活；
 * 如果活细胞周围八个位置有超过三个活细胞，则该位置活细胞死亡；
 * 如果死细胞周围正好有三个活细胞，则该位置死细胞复活；
 * 根据当前状态，写一个函数来计算面板上所有细胞的下一个（一次更新后的）状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的，其中细胞的出生和死亡是同时发生的。
 * <p>
 *  
 * <p>
 * 示例：
 * <p>
 * 输入：
 * [
 *   [0,1,0],
 *   [0,0,1],
 *   [1,1,1],
 *   [0,0,0]
 * ]
 * 输出：
 * [
 *   [0,0,0],
 *   [1,0,1],
 *   [0,1,1],
 *   [0,1,0]
 * ]
 *  
 * <p>
 * 进阶：
 * <p>
 * 你可以使用原地算法解决本题吗？请注意，面板上所有格子需要同时被更新：你不能先更新某些格子，然后使用它们的更新后的值再更新其他格子。
 * 本题中，我们使用二维数组来表示面板。原则上，面板是无限的，但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题？
 *
 * @ProjectName: leetcode
 * @Package: com.linyaonan.leetcode.medium._289
 * @ClassName: GameOfLife
 * @Author: linyaonan
 * @Date: 2020/4/2 15:02
 */
public class GameOfLife {

    public void gameOfLife(int[][] board) {
        if (board == null || board.length == 0 || board[0].length == 0) {
            return;
        }
        int[] x = new int[]{0, 0, 1, -1, 1, 1, -1, -1};
        int[] y = new int[]{1, -1, 0, 0, 1, -1, 1, -1};
        int maxX = board.length - 1;
        int maxY = board[0].length - 1;
        int[][] temp = new int[maxX + 1][maxY + 1];
        // 对原始数组进行遍历
        for (int i = 0; i <= maxX; i++) {
            for (int j = 0; j <= maxY; j++) {
                int beforeCell = board[i][j];
                int aliveCount = 0;
                // 对每个坐标的8个位置进行统计活细胞数量
                for (int k = 0; k < 8; k++) {
                    int xIndex = x[k] + i;
                    int yIndex = y[k] + j;
                    if (xIndex >= 0 && xIndex <= maxX && yIndex >= 0 && yIndex <= maxY && board[xIndex][yIndex] == 1) {
                        aliveCount++;
                    }
                }
                temp[i][j] = getThisCellAlive(beforeCell, aliveCount);
            }
        }
        for (int i = 0; i < temp.length; i++) {
            for (int j = 0; j < temp[i].length; j++) {
                board[i][j] = temp[i][j];
            }
        }
    }

    private int getThisCellAlive(int beforeAlive, int count) {
        // 原先是存活状态
        if (beforeAlive == 1) {
            // 小于两个细胞死亡
            if (count < 2) {
                return 0;
            } else if (count == 2 || count == 3) {
                // 2个或者3个，细胞存活
                return 1;
            } else {
                // 大于三个，细胞死亡
                return 0;
            }
        } else {
            if (count == 3) {
                // 细胞复活
                return 1;
            } else {
                return 0;
            }
        }
    }
}
